package cn.edu.scau.cmi.ema.dao;

import cn.edu.scau.cmi.ema.base.CmiPagination;
import cn.edu.scau.cmi.ema.domain.User;
import cn.edu.scau.cmi.ema.util.CmiSqlUtil;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.*;

@Repository("UserDAO")
@Transactional
public class UserDAOImpl extends AbstractJpaDao<User> implements UserDAO {

	private final static Set<Class<?>> dataTypes = new HashSet<Class<?>>(Arrays.asList(new Class<?>[] { User.class }));

	@PersistenceContext()
	private EntityManager entityManager;

	public UserDAOImpl() {
		super();
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public Set<Class<?>> getTypes() {
		return dataTypes;
	}

	@Transactional
	public User findUserById(Integer id) throws DataAccessException {

		return findUserById(id, -1, -1);
	}

	@Transactional
	public User findUserById(Integer id, int startResult, int maxRows) throws DataAccessException {
		try {
			Query query = createNamedQuery("findUserById", startResult, maxRows, id);
			return (User) query.getSingleResult();
		} catch (NoResultException nre) {
			return null;
		}
	}

	@Transactional
	public Set<User> findUserByName(String name) throws DataAccessException {

		return findUserByName(name, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByName(String name, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByName", startResult, maxRows, name);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByNameContaining(String name) throws DataAccessException {

		return findUserByNameContaining(name, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByNameContaining(String name, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByNameContaining", startResult, maxRows, name);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByUsername(String username) throws DataAccessException {

		return findUserByUsername(username, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByUsername(String username, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByUsername", startResult, maxRows, username);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByUsernameContaining(String username) throws DataAccessException {

		return findUserByUsernameContaining(username, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByUsernameContaining(String username, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByUsernameContaining", startResult, maxRows, username);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByPassword(String password) throws DataAccessException {

		return findUserByPassword(password, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByPassword(String password, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByPassword", startResult, maxRows, password);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByPasswordContaining(String password) throws DataAccessException {

		return findUserByPasswordContaining(password, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByPasswordContaining(String password, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByPasswordContaining", startResult, maxRows, password);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByFirstname(String firstname) throws DataAccessException {

		return findUserByFirstname(firstname, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByFirstname(String firstname, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByFirstname", startResult, maxRows, firstname);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByFirstnameContaining(String firstname) throws DataAccessException {

		return findUserByFirstnameContaining(firstname, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByFirstnameContaining(String firstname, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByFirstnameContaining", startResult, maxRows, firstname);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByLastname(String lastname) throws DataAccessException {

		return findUserByLastname(lastname, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByLastname(String lastname, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByLastname", startResult, maxRows, lastname);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByLastnameContaining(String lastname) throws DataAccessException {

		return findUserByLastnameContaining(lastname, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByLastnameContaining(String lastname, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByLastnameContaining", startResult, maxRows, lastname);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByGender(String gender) throws DataAccessException {

		return findUserByGender(gender, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByGender(String gender, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByGender", startResult, maxRows, gender);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByGenderContaining(String gender) throws DataAccessException {

		return findUserByGenderContaining(gender, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByGenderContaining(String gender, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByGenderContaining", startResult, maxRows, gender);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByBirthday(Calendar birthday) throws DataAccessException {

		return findUserByBirthday(birthday, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByBirthday(Calendar birthday, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByBirthday", startResult, maxRows, birthday);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByCareer(String career) throws DataAccessException {

		return findUserByCareer(career, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByCareer(String career, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByCareer", startResult, maxRows, career);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByCareerContaining(String career) throws DataAccessException {

		return findUserByCareerContaining(career, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByCareerContaining(String career, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByCareerContaining", startResult, maxRows, career);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByEmail(String email) throws DataAccessException {

		return findUserByEmail(email, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByEmail(String email, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByEmail", startResult, maxRows, email);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByEmailContaining(String email) throws DataAccessException {

		return findUserByEmailContaining(email, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByEmailContaining(String email, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByEmailContaining", startResult, maxRows, email);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByPhone(String phone) throws DataAccessException {

		return findUserByPhone(phone, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByPhone(String phone, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByPhone", startResult, maxRows, phone);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByPhoneContaining(String phone) throws DataAccessException {

		return findUserByPhoneContaining(phone, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByPhoneContaining(String phone, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByPhoneContaining", startResult, maxRows, phone);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByCellphone(String cellphone) throws DataAccessException {

		return findUserByCellphone(cellphone, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByCellphone(String cellphone, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByCellphone", startResult, maxRows, cellphone);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByCellphoneContaining(String cellphone) throws DataAccessException {

		return findUserByCellphoneContaining(cellphone, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByCellphoneContaining(String cellphone, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByCellphoneContaining", startResult, maxRows, cellphone);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByQq(String qq) throws DataAccessException {

		return findUserByQq(qq, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByQq(String qq, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByQq", startResult, maxRows, qq);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByQqContaining(String qq) throws DataAccessException {

		return findUserByQqContaining(qq, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByQqContaining(String qq, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByQqContaining", startResult, maxRows, qq);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByWechat(String wechat) throws DataAccessException {

		return findUserByWechat(wechat, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByWechat(String wechat, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByWechat", startResult, maxRows, wechat);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByWechatContaining(String wechat) throws DataAccessException {

		return findUserByWechatContaining(wechat, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByWechatContaining(String wechat, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByWechatContaining", startResult, maxRows, wechat);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByEnabled(Boolean enabled) throws DataAccessException {

		return findUserByEnabled(enabled, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByEnabled(Boolean enabled, int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findUserByEnabled", startResult, maxRows, enabled);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByDescription(String description) throws DataAccessException {

		return findUserByDescription(description, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByDescription(String description, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByDescription", startResult, maxRows, description);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public Set<User> findUserByDescriptionContaining(String description) throws DataAccessException {

		return findUserByDescriptionContaining(description, -1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByDescriptionContaining(String description, int startResult, int maxRows)
			throws DataAccessException {
		Query query = createNamedQuery("findUserByDescriptionContaining", startResult, maxRows, description);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@Transactional
	public User findUserByPrimaryKey(Integer id) throws DataAccessException {
		return findUserByPrimaryKey(id, -1, -1);
	}

	@Transactional
	public User findUserByPrimaryKey(Integer id, int startResult, int maxRows) throws DataAccessException {
		try {
			Query query = createNamedQuery("findUserByPrimaryKey", startResult, maxRows, id);
			return (User) query.getSingleResult();
		} catch (NoResultException nre) {
			return null;
		}
	}

	@Transactional
	public Set<User> findUsersByIds(Set<Integer> ids) throws DataAccessException {
		try {
			Query query = createNamedQuery("findUsersByIds", -1, -1, ids);
			return new HashSet(query.getResultList());
		} catch (NoResultException nre) {
			return null;
		}
	}

	@Transactional
	public Set<User> findAllUsers() throws DataAccessException {

		return findAllUsers(-1, -1);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findAllUsers(int startResult, int maxRows) throws DataAccessException {
		Query query = createNamedQuery("findAllUsers", startResult, maxRows);
		return new LinkedHashSet<User>(query.getResultList());
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public Set<User> findUserByCompositeProperities(String sql, int startResult, int maxRows) {
		return new LinkedHashSet<User>(createQuery(sql, startResult, maxRows).getResultList());
	}

	@Transactional
	public Set<User> findUsersByDetachedCriteria(CmiPagination page) throws DataAccessException {
		DetachedCriteria detachedCriteria = CmiSqlUtil.createDetachedCriteria(page, User.class);
		Session session = (Session) entityManager.getDelegate();
		Set<User> users = new HashSet(detachedCriteria.getExecutableCriteria(session)
				.setFirstResult(page.getSearchBeginCursor()).setMaxResults(page.getPaginationSize()).list());

		return users;
	}

	@Transactional
	public User findUserByPhysicalPrimaryKey(String name, Calendar birthday, String email) throws DataAccessException {
		return findUserByPhysicalPrimaryKey(name, birthday, email, -1, -1);
	}

	@Transactional
	public User findUserByPhysicalPrimaryKey(String name, Calendar birthday, String email, int startResult, int maxRows)
			throws DataAccessException {
		try {
			Query query = createNamedQuery("findUserByPhyscialPrimaryKey", startResult, maxRows, name, birthday, email);
			return (User) query.getSingleResult();
		} catch (NoResultException nre) {
			return null;
		}
	}

	public boolean canBeMerged(User entity) {
		return true;
	}
}
